package com.server.rule.data;



import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.jdom.Element;
import org.jdom.JDOMException;
import com.shared.rule.TypeDataRule;

import com.server.rule.data.loader.InformationLoader;


public class Data {

	
	private Map<String,DataElement> mapDataElement;
	private List<InformationLoader> listInformationLoaders;
	
	
	public Data() {		
		mapDataElement = new HashMap<String, DataElement>();	
		listInformationLoaders=new ArrayList<InformationLoader>();
	}	
	
	
	public Data(Map<String,DataElement> mapDataElement){
		this.mapDataElement = mapDataElement;		
	}
	
	public DataElement get(String label){
		return mapDataElement.get(label);
	}
	
	public Object getValue(String label){
		return mapDataElement.get(label).getValue().getValue();
	}
	
		
	public TypeDataRule getType(String label){		
		return mapDataElement.get(label).getTypeData();
	}
	
	public void put(String label,Double d,boolean isParameter){
		mapDataElement.put(label,new NumericDataElement(d,isParameter) );		
	}
	
	public void put(String label,String s,boolean isParameter){
		mapDataElement.put(label, new NominalDataElement(s,isParameter));
	}
	
	public void put(String label,Boolean s,boolean isParameter){	
		if(s==null){
			mapDataElement.put(label, new BooleanDataElement(isParameter));		
		}else{
			mapDataElement.put(label, new BooleanDataElement(s,isParameter));	
		}
	}
	
	public void merge(Data data){
		mapDataElement.putAll(data.mapDataElement);		
	}
	
	public List<String> getLabel(){
		List<String> list = new ArrayList<String>();
		for(String label : mapDataElement.keySet()){
			list.add(label);
		}
		return list;
	}
	
	public List<TypeDataRule> getTypeData(){
		List<TypeDataRule> list = new ArrayList<TypeDataRule>();
		for(DataElement dataElement : mapDataElement.values()){
			list.add(dataElement.getTypeData());
		}		
		return list;
	}
	
	public void clear(){
		mapDataElement.clear();		
	}

	public void verifyLabel(Data entryData) throws ExceptionTypeData {
		for(String key : mapDataElement.keySet()){			
			if(!mapDataElement.get(key).isParameter){
				Boolean asMatch = false;
				for(String entryKey : entryData.mapDataElement.keySet()){
					if(key.equals(entryKey)) asMatch = true;
				}
				if(!asMatch) throw new ExceptionTypeData("Mauvais type de données: "+key+" non présente dans les données en entrée");
			}
		}
	}
	
	public void verifyNotAnyNull(List<String> usedData) throws NullPointerException{
		for(String keyUsed : usedData){	
			
			if(getValue(keyUsed)==null) throw new NullPointerException(keyUsed+" est null ou absente dans les donnes d'entrées");
		}
	}
	
	public void verify(Data entryData,List<String> usedData) throws ExceptionTypeData{
		verifyLabel(entryData);		
		entryData.verifyNotAnyNull(usedData);
	}
	
	public void copyParam(Data entryData){
		for(String key : mapDataElement.keySet()){	
			if(mapDataElement.get(key).isParameter){
				entryData.mapDataElement.put(key, mapDataElement.get(key));
			}
		}
	}
	
	public void verifyParamNotNull(){
		for(String entryKey : mapDataElement.keySet()){
			if(get(entryKey).isParameter()){
				if(getValue(entryKey)==null) throw new NullPointerException("Le paramètre "+entryKey+" n'est pas defini");
			}
		}
	}
	
	public boolean isDataStructure(){		
		boolean b = true;
		try{
			 verifyParamNotNull();
		}catch(NullPointerException e){
			b=false;
		}
		for(String entryKey : mapDataElement.keySet()){
			if(!get(entryKey).isParameter()){
				if(getValue(entryKey)!=null) b=false;
			}
		}
		return b;
	}
	
	public Element getXMLElement(){		
		Element xmlElement = new Element("DecisionMakerData");
		for(int i=0;i<mapDataElement.size();i++){			
			Element elementTemp = new Element("data");			
			elementTemp.setAttribute("label",getLabel().get(i));
			elementTemp.setAttribute("type",getTypeData().get(i).toString());
			if(getValue(getLabel().get(i))!=null){
				elementTemp.setAttribute("value",getValue(getLabel().get(i)).toString());
			}
			xmlElement.addContent(elementTemp);
		}
		return xmlElement;
	}
	
	
	
	public void generateFromXML(Element xmlElement){
		
		Iterator iteratorOnChildren = (xmlElement.getChildren()).iterator();
		while(iteratorOnChildren.hasNext()){
			Element elementTemp = (Element) iteratorOnChildren.next();	
			
			if(elementTemp.getAttributeValue("type").equals(TypeDataRule.NUMERIC.toString())){
				if(elementTemp.getAttributeValue("value")!=null){
					put(elementTemp.getAttributeValue("label"),Double.parseDouble(elementTemp.getAttributeValue("value")),true);				
				}else{
					put(elementTemp.getAttributeValue("label"), (Double) null,false);				
				}
				
			}else if(elementTemp.getAttributeValue("type").equals(TypeDataRule.NOMINAL.toString())) {
				if(elementTemp.getAttributeValue("value")!=null){
					put(elementTemp.getAttributeValue("label"), elementTemp.getAttributeValue("value"),true);
				}else{
					put(elementTemp.getAttributeValue("label"), (String) null,false);
				}
			}else{
				if(elementTemp.getAttributeValue("value")!=null){
					put(elementTemp.getAttributeValue("label"),(Boolean) Boolean.valueOf(elementTemp.getAttributeValue("value")),true);
				}else{
					put(elementTemp.getAttributeValue("label"), (Boolean) null,false);
				}
			}
		}
	}


	/**
	 * @param listInformationLoaders the listInformationLoaders to set
	 */
	public void setListInformationLoaders(List<InformationLoader> listInformationLoaders) {
		this.listInformationLoaders = listInformationLoaders;
	}


	/**
	 * @return the listInformationLoaders
	 */
	public List<InformationLoader> getListInformationLoaders() {
		return listInformationLoaders;
	}
	
	public void addInformationLoader(InformationLoader informationLoader){
		listInformationLoaders.add(informationLoader);
	}
	
	public void loadStructure() throws IllegalArgumentException, JDOMException, IOException, IllegalAccessException{
		for(InformationLoader i : listInformationLoaders){
			i.loadInformationStructure(this);
		}
	}
	
	public void loadData() throws IllegalArgumentException, IllegalAccessException, JDOMException, IOException{
		for(InformationLoader i : listInformationLoaders){
			i.loadInformation(this);
		}
	}
	
	public Map<String,TypeDataRule> getMapType(){
		Map<String,TypeDataRule> map = new HashMap<String, TypeDataRule>();
		for(String entryKey : mapDataElement.keySet()){
			map.put(entryKey, getType(entryKey));
		}
		return map;
	}
	
}
